package org.videopractice.network.message;

import org.videopractice.network.exception.IllegalMessageException;
import org.videopractice.network.handler.IService;
import org.videopractice.network.handler.service.LiveDataService;
import org.videopractice.network.message.request.HeartBeatRequest;
import org.videopractice.network.message.request.LiveDataRequest;

import java.util.HashMap;
import java.util.Map;

public enum MessageCode {

    /** 心跳包 */
    HeartBeatRequest((short) 1000, (short) 0, Boolean.FALSE, Boolean.TRUE, HeartBeatRequest.class, null),
    LiveDataRequest((short) 1001, (short) 0, Boolean.FALSE, Boolean.TRUE, LiveDataRequest.class, LiveDataService.class);

    // 消息编码-消息编码对象映射
    private static Map<Short, MessageCode> CODE_CLASS_MAP = new HashMap<>();
    // 消息编码-消息对象映射
    private static Map<Short, Class<? extends BaseDto>> MESSAGE_CLASS_MAP = new HashMap<>();
    // 消息编码-消息处理服务映射
    private static Map<Short, Class<? extends IService>> SERVICE_CLASS_MAP = new HashMap<Short, Class<? extends IService>>();

    private short code;                             // 消息编码
    private short refCode;                          // 关联消息编码，为0时表示没有关联报文
    private boolean compression;                    // 是否开启gzip压缩(默认关闭)，消息体数据大的时候才开启，非常小的包压缩后体积反而变大，而且耗时
    private boolean jsonCoverToObject;              // 消息内容是否从JSON格式转为对象
    private Class<? extends BaseDto> messageClass;  // 消息对象
    private Class<? extends IService> serviceClass; // 消息处理服务

    /************************************************************************************/
    public short getCode() {
        return code;
    }

    public void setCode(short code) {
        this.code = code;
    }

    public short getRefCode() {
        return refCode;
    }

    public void setRefCode(short refCode) {
        this.refCode = refCode;
    }

    public boolean isCompression() {
        return compression;
    }

    public void setCompression(boolean compression) {
        this.compression = compression;
    }

    public boolean isJsonCoverToObject() {
        return jsonCoverToObject;
    }

    public void setJsonCoverToObject(boolean jsonCoverToObject) {
        this.jsonCoverToObject = jsonCoverToObject;
    }

    public Class<? extends BaseDto> getMessageClass() {
        return messageClass;
    }

    public void setMessageClass(Class<? extends BaseDto> messageClass) {
        this.messageClass = messageClass;
    }

    public Class<? extends IService> getServiceClass() {
        return serviceClass;
    }

    public void setServiceClass(Class<? extends IService> serviceClass) {
        this.serviceClass = serviceClass;
    }
    /************************************************************************************/

    MessageCode(short code, short refCode, boolean compression, boolean jsonCoverToObject,
                Class<? extends BaseDto> messageClass, Class<? extends IService> serviceClass) {
        this.code = code;
        this.refCode = refCode;
        this.compression = compression;
        this.jsonCoverToObject = jsonCoverToObject;
        this.messageClass = messageClass;
        this.serviceClass = serviceClass;
    }

    /**
     * 初始化
     */
    public static void init() {
        for (MessageCode messageCode : MessageCode.values()) {
            CODE_CLASS_MAP.put(messageCode.getCode(), messageCode);
            MESSAGE_CLASS_MAP.put(messageCode.getCode(), messageCode.getMessageClass());
            SERVICE_CLASS_MAP.put(messageCode.getCode(), messageCode.getServiceClass());
        }
    }

    /**
     * 创建一个新的消息对象
     * @param code
     * @return
     */
    public final static Message createNewMessage(short code) {
        MessageCode messageCode = CODE_CLASS_MAP.get(code);
        if (messageCode == null) {
            throw new IllegalMessageException("非法编码：" + code);
        }

        return new Message(messageCode);
    }

    /**
     * 根据消息编码获取消息编码定义
     * @param code 消息编码
     * @return
     */
    public static MessageCode getMessageCodeByCode(short code) {
        MessageCode messageCode = CODE_CLASS_MAP.get(code);
        if (messageCode == null) {
            throw new IllegalMessageException("没有找到消息编码[" + code + "]");
        }
        return messageCode;
    }

    /**
     * 根据消息编码判断是否存对应消息定义
     * @param code 消息编码
     * @return
     */
    public static boolean exist(short code) {
        if (code == (short) 0) {
            return Boolean.FALSE;
        }
        return CODE_CLASS_MAP.get(code) != null;
    }

    /**
     * 根据消息编码获取消息对象
     * @param code
     * @return
     */
    public static Class getMessageClassByCode(short code) {
        Class clazz = MESSAGE_CLASS_MAP.get(code);
        if (clazz == null) {
            throw new IllegalMessageException("没有找到消息编码[" + code + "]对应的消息对象");
        }
        return clazz;
    }

    /**
     * 根据消息编码获取消息处理服务
     * @param messageCode
     * @return
     */
    public static Class<? extends IService> getServiceClassByCode(MessageCode messageCode) {
        return getServiceClassByCode(messageCode.getCode());
    }

    /**
     * 根据消息编码获取消息处理服务
     * @param code
     * @return
     */
    public static Class<? extends IService> getServiceClassByCode(short code) {
        Class<? extends IService> clazz = SERVICE_CLASS_MAP.get(code);
        if (clazz == null) {
            throw new IllegalMessageException("没有找到消息编码[" + code + "]对应的消息处理服务");
        }
        return clazz;
    }

}
